package com.smartian.scan.filesearch.dispatchers;

import com.smartian.scan.filesearch.DispatcherManager;
import com.smartian.scan.filesearch.bean.PathFile;
import com.smartian.scan.filesearch.bean.TreeNodeFile;
import com.smartian.scan.filesearch.interfaces.IDispatcher;
import com.smartian.scan.filesearch.interfaces.IFilter;
import com.smartian.scan.filesearch.interfaces.ISearchCallback;
import com.smartian.scan.filesearch.interfaces.TreeAdapter;
import com.smartian.scan.filesearch.task.exectors.TaskExecutors;
import com.smartian.scan.filesearch.task.runnable.TreeSearchRunnable;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;


public class TreeSearchTaskDispatcher implements IDispatcher, Runnable, TreeAdapter {

    private long timeout = 0l;
    private List<String> beginPaths = null;
    private List<IFilter> filters = null;
    private ISearchCallback callback;

    private AtomicLong mTaskCount;
    private AtomicLong mFinishTaskCount;
    private volatile boolean isTerminal = false;
    private long startTime = 0l;


    @Override
    public void shutdown() {
        isTerminal = true;
    }

    @Override
    public void start() {
        mTaskCount = new AtomicLong();
        mFinishTaskCount = new AtomicLong();
        startTime = System.currentTimeMillis();
        TaskExecutors.THREAD_POOL_EXECUTOR.execute(this);
    }

    @Override
    public void setBeginPaths(List<String> dirs) {
        this.beginPaths = dirs;
    }

    @Override
    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }

    @Override
    public void setFilters(List<IFilter> filters) {
        this.filters = filters;
    }

    @Override
    public void setCallback(ISearchCallback callback) {
        this.callback = callback;
    }


    @Override
    public void run() {

        onStartDispatch();
        dispatch();
        onStopDispatch();

    }

    private void dispatch() {

        if (beginPaths == null || beginPaths.size() == 0) {
            onError("没有提供扫描路径");
            return;
        }
        TreeNodeFile treeNodeFile = new TreeNodeFile();
        treeNodeFile.buildTree(beginPaths);

        executeTask(treeNodeFile);

        do {
            synchronized (this) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        } while (!shouldTerminal());
    }

    private synchronized boolean shouldTerminal() {
        if (isTimeout() || isTerminal) {
            return true;
        }

        if (mFinishTaskCount.get() == mTaskCount.get()) {
            return true;
        }
        return false;
    }

    private boolean isTimeout() {
        if (timeout <= 0) {
            return false;
        }
        return System.currentTimeMillis() - startTime > timeout;
    }

    private void executeTask(TreeNodeFile treeNodeFile) {
        mTaskCount.incrementAndGet();
        TaskExecutors.THREAD_POOL_EXECUTOR.execute(new TreeSearchRunnable(this, treeNodeFile));
    }

    private void onError(String msg) {
        if (callback != null) callback.onError(null, new IllegalArgumentException(msg));
    }

    private void onStopDispatch() {
        DispatcherManager.shareInstance().shutdownDispatcher(this);
        if (callback == null) return;
        callback.onStopSearch();
    }

    private void onStartDispatch() {
        if (callback == null) return;
        callback.onStartSearch();

    }


    @Override
    public void onStartSearchTree(String fullPath) {
        System.out.println("SearchTree " + "开始检索:" + fullPath);
    }

    @Override
    public void onStopSearchTree(String fullPath) {
        System.out.println("SearchTree" + " 停止检索:" + fullPath);
        mFinishTaskCount.incrementAndGet();

        synchronized (this) {
            notify();
        }

    }

    @Override
    public void onSearchedTreeFiles(List<File> scanFiles) {
        if (callback == null) return;
        List<File> resultFiles = onFilterIntercept(scanFiles);

        if (resultFiles == null) return;

        List<PathFile> pathFiles = new ArrayList<>();
        for (int i = 0; i < resultFiles.size(); i++) {

            File f = resultFiles.get(i);
            PathFile pf = PathFile.build(resultFiles.get(i), f.getAbsolutePath());
            pathFiles.add(pf);
        }
        callback.onFile(pathFiles);
    }


    private List<File> onFilterIntercept(List<File> files) {

        if (files == null || filters == null || filters.size() == 0) return files;

        Iterator<File> iterator = files.iterator();
        if (!iterator.hasNext()) return files;

        do {
            File pathFile = iterator.next();


            for (int i = 0; i < filters.size(); i++) {
                IFilter filter = filters.get(i);
                if (!filter.isAcceptable(pathFile)) {
                    iterator.remove();
                    continue;
                }
            }

        } while (iterator.hasNext());

        return files;
    }

    @Override
    public void onDisptachTree(TreeNodeFile treeNode) {
        executeTask(treeNode);
    }


}
